package bsserver.response;

import bsserver.Main;
import bsserver.Request;
import bsserver.RequestURI;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

/**
 * Response class for handling POST Requests
 * @author tblackstone
 */
public class POSTResponse extends Response {

    /**
     * Create a new Response to a POST request
     * @param r the POST Request which caused this Response to be generated
     */
    public POSTResponse(Request r) {
        super(r);
    }

    /**
     * Process a POST Request to determine how to respond to it
     * @param r the Request to process
     * @return an appropriate Response object
     */
    public static Response process(Request r) {

        Response response;
        RequestURI requestURI = r.getRequestURI();

        // Check Resource Permissions
        String validUser = findClientPermissions(r);

        if(!r.getAuthInfo().isReadable()) {
            return new ErrorResponse(r, 404);
        }

        if (validUser == null) {
            Response authRequiredResponse = new ErrorResponse(r, 401);
            authRequiredResponse.setHeader("WWW-Authenticate",
                    "Basic realm=\"" + r.getAuthInfo().getAuthName() + "\"");
            return authRequiredResponse;
        }
        r.setRemoteUser(validUser);


        if (!requestURI.resourceExists()) {
            return new ErrorResponse(r, 404);

        } else if (requestURI.isScript()) {
            if (r.getAuthInfo().isExecutable()) {
                response = new ScriptResponse(r);
                return response;
            } else {
                return new ErrorResponse(r, 403);
            }
        } else {

            response = new POSTResponse(r);
            // Resource is a file
            File resource = new File(requestURI.getAbsolutePath());
            byte[] body = null;

            try {
                body = POSTResponse.readFile(resource);
            } catch (IOException ex) {
                return new ErrorResponse(r, 500);
            }
            // File too large to read
            if (body == null) {
                return new ErrorResponse(r, 413);
            }

            // Set Last-Modifed Header
            long modifiedDate = resource.lastModified();
            SimpleDateFormat f = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z");
            f.setTimeZone(TimeZone.getTimeZone("GMT"));
            String date = f.format(new Date(modifiedDate));
            response.setHeader("Last-Modified", date);

            // Set Content-type header
            String contentType = Main.HttpdConfig.get("DefaultType");
            if (contentType == null) {
                contentType = "text/plain";
            }
            int extensionPos = resource.getName().lastIndexOf(".");
            if (extensionPos != -1) {
                String extension = resource.getName().substring(extensionPos + 1);
                String newType = Main.MimeType.getType(extension);
                if (newType != null) {
                    contentType = newType;
                }
            }
            response.setHeader("Content-Type", contentType);

            response.setBody(body);
            response.setStatus(200);

            return response;
        }
    }

    private static byte[] readFile(File in) throws IOException {

        InputStream is = new FileInputStream(in);

        long length = in.length();
        if (length > Integer.MAX_VALUE) {
            // File is too large
            return null;
        }

        byte[] bytes = new byte[(int) length];

        // Read in the bytes
        int offset = 0;
        int numRead = 0;
        while (offset < bytes.length && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
            offset += numRead;
        }

        // Ensure all the bytes have been read in
        if (offset < bytes.length) {
            throw new IOException("Could not completely read file " + in.getName());
        }

        // Close the input stream and return bytes
        is.close();
        return bytes;
    }
}
